feat(examples): add Kubernetes GPU autoscaling recipe - #111
Conversation
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thanks for moving this Kubernetes GPU autoscaling work into the community repository. The static checks and contract tests are in good shape, but two items need to be completed before approval:
- Please provide a documented live Kubernetes/GPU validation of the core workflow. The recipe's primary behavior is GPU-backed inference and HPA scaling, but the PR currently states that no live Kubernetes/H100 validation was run. At minimum, validate deployment, authenticated inference, the custom GPU metric, and a scale-up/scale-down cycle on a suitable cluster.
- Please complete the contributor review of the agent-generated text and check the corresponding PR-template item. The PR currently marks this as required before merge.
Once those are complete, we can reassess the PR for approval.
Thanks for the prompt reply: 1. I had to give up the DGX H100 test, because the admin already setup the cluster to have GPU time slicing to 4 replicas per GPU, which will affect my K8s pod and GPU utilization per GPU, this H100 test is pending on if the cluster admin agree to change GPU operator to cancel the GPU time slicing to exclusive GPU allocation. Instead, I had to go back to the same hardware I used for PR7459: Brev 4xL40S on AWS: NVIDIA L40S (44.70 GiB) 4 GPUs x 48 CPUs 384 GiB RAM |
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thank you for the update. The documented 4× L40S run now covers the chart deployment, authenticated inference, GPU metric, HPA scale-up/scale-down, and Envoy LeastRequest distribution. The contributor and documentation-review checklist items are also complete on the current head.
Two items still need attention before approval:
- Separate the internal cleartext route from externally exposed Envoy Services. The current Gateway always creates a hostname-unrestricted HTTP listener and OpenShell route on port 80. When
ingress.gateway.serviceTypeis changed toNodePortorLoadBalancer, that same listener becomes externally reachable even when TLS is configured. Requests using another Host value or the load-balancer IP can select the OpenShell route instead of the hostname-specific HTTPS redirect, bypassing Gateway TLS and Basic authentication while carrying the reusable Bearer credential and inference traffic over cleartext. Please either use a separate ClusterIP-only Gateway/dataplane for OpenShell and a distinct TLS-only external Gateway, or rejectNodePort/LoadBalancerwhile the internal HTTP listener is present. Add a render/security contract test for the chosen boundary. - Complete or narrow the end-to-end validation claim. The L40S evidence validates the GPU chart and Envoy path, but the PR still advertises a NemoClaw/OpenShell sandbox workflow and explicitly states that sandbox creation was not live-validated. Please run the actual sandbox creation and inference path through
https://inference.local, including a model request from the sandbox, or narrow the recipe's advertised scope so the unvalidated sandbox integration is not presented as a completed workflow.
The available local security, Kubernetes, inference-authentication, syntax, SPDX, taxonomy, and diff checks pass on 196fba6.
…ineage Link NemoClaw #7459 / community NVIDIA#111 and summarize the CPU-only OpenShell sandbox top layer plus the ingress-nginx → Envoy LeastRequest change. Signed-off-by: maggiezha <maggiez@nvidia.com>
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thank you for the latest updates. The earlier Envoy exposure and end-to-end OpenShell validation blockers are resolved, and the available DCO, SPDX, taxonomy, syntax, authentication, Kubernetes, and security checks pass on 0c25e5a.
Two items remain before approval:
- Fix the broken upstream chart link. The README links
NemoClaw GPU autoscaling charttoNVIDIA/NemoClaw/tree/main/deploy/helm/gpu_autoscaling_k8s, but that path returns 404 because NVIDIA/NemoClaw#7459 is still open. Please link to the immutable source commit (77334ccbbadba2c5079fe9e99fe80a3cddc846b5) or directly to PR #7459 instead ofmain. - Reject invalid Gateway path types.
nemoclaw-gpu.httpPathMatchTypecurrently maps every value other thanExacttoPathPrefix. A typo or unsupported value therefore silently broadens the route instead of failing. Please accept only the supportedPrefixandExactinputs, fail rendering for anything else, and add a render-contract case for the invalid-value failure.
Once these are addressed and the final documentation-review evidence identifies the exact reviewed head, this should be ready for approval.
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thank you for the additional validation and documentation updates. The 4× L40S result is sufficient for this experimental recipe; H100 validation can remain follow-up work and does not need to block this PR. The available repository checks pass on b4d8dc6.
The previously requested items are still outstanding:
- The README’s
NemoClaw GPU autoscaling chartlink still points tomain, where that path returns 404. Please use the immutable77334ccbbadba2c5079fe9e99fe80a3cddc846b5source or NVIDIA/NemoClaw#7459. nemoclaw-gpu.httpPathMatchTypestill maps every value other thanExacttoPathPrefix. Please accept onlyPrefixandExact, fail for unsupported values, and add the requested invalid-value render test.- The documentation-review evidence still says “see latest commits” instead of identifying the exact final reviewed head.
The latest commits also add switchable latency and request-rate HPA modes. This is a substantial, unvalidated scope expansion, so I recommend removing it from this PR and landing it separately after focused validation. In its current form:
- The rolling latency gauges retain their last samples indefinitely; a high value can remain after traffic stops and prevent scale-down.
- The
nemoclaw_llm_request_rateadaptermetricsQueryomitsresult="success", so it can aggregate error requests despite being documented as successful-completion rate. hpa-load-test.shremains GPU-utilization-specific in its load model and reporting, so it does not validate the alternate modes it now advertises.- Render coverage exercises only
latency_p95, not every new mode, invalid mode handling, or the adapter-query semantics.
Please keep this PR on the validated GPU-utilization path, address the three outstanding procedural/render items, and move alternate HPA signals to a follow-up PR with targeted tests and live scale-up/scale-down evidence.
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thanks for the latest updates. The values-overlay consolidation is internally consistent, and the available repository, syntax, security, Kubernetes, and authentication contract checks pass on 5146e8b.
The requested changes are still outstanding:
- The README link for the NemoClaw GPU autoscaling chart still points to a path on
mainthat returns 404. Please link to immutable source commit77334ccbbadba2c5079fe9e99fe80a3cddc846b5or NVIDIA/NemoClaw#7459. nemoclaw-gpu.httpPathMatchTypestill maps every value other thanExacttoPathPrefix. Please accept onlyPrefixandExact, fail rendering for anything else, and add the invalid-value render-contract test.- The documentation-review evidence still says “see latest commits” rather than naming the exact reviewed head.
- The alternate latency and request-rate HPA modes remain in this PR without the requested focused validation. Please move them to a follow-up PR, or address the stale latency-gauge behavior, successful-request query filtering, mode-aware load testing, and complete render/adapter coverage.
- The newly restored screenshots show a specific Brev host name and local workspace path in the terminal prompt. Please crop or redact those prompt lines before publishing them; this also needs to align with the PR declaration that nonpublic host names and workspace paths are excluded.
The branch is also one commit behind main; please update it after the content changes are complete.
Ship an experimental community recipe that runs authenticated Ollama on GPU pods, scales replicas with Kubernetes HPA (GPU utilization by default, switchable metrics), and optionally load-balances with Envoy LeastRequest. Includes OpenShell sandbox path, MicroK8s registry notes, contract tests, and L40S validation screenshots.
d08bfc4 to
58e3d19
Compare
Thanks! working on validating latency related metrics, and if not working well I will remove them. Sorry I committed too many times. |
Thanks! working on addressing them and testing/validating. Will update here when I finish all of them and request your final review |
Link the NemoClaw source to #7459/77334cc, reject unsupported ingress.pathType values, remove unvalidated latency/request_rate HPA modes from this recipe, and crop host/path prompts from screenshots.
tested latency as HPA metric and added a screenshot related to average per-pod latency. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Clarified text regarding version alignment and HPA metrics. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Validate and document average per-pod GPU util >40% and latency >3000 ms as the two HPA examples, clarify latency proxy timing and custom metrics, normalize HPA quantity display, and stop load generators after max replicas hold.
Keep the GitHub-uploaded latency screenshot and original captions unchanged.
Reformatted README for improved readability and clarity. Updated examples and descriptions for HPA metrics and Envoy usage. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Updated image source for HPA scaling example and clarified load balancing instructions. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Reorganize and update script section in README for clarity. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
|
Update: I tested latency as another metric for HPA and added a screenshot for it in Readme. I also manually polished Readme and removed some redundant code/scripts. I think the above points are addressed, but pls let me know if there ia anything else need to change. Thank you! |
|
@coderabbitai review |
Uninstall plus reinstall covers release teardown; drop the recovery wrapper and its README/contract references.
|
tried to get CodeRabbit work here but not sure why it didn't work, it worked for my older PR NVIDIA/NemoClaw#7459 though |
Clarified the purpose and functionality of the Kubernetes GPU autoscaling recipe, detailing the architecture, scaling metrics, and optional Envoy Gateway usage. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thanks for the updates. The branch is current with main, the Gateway path-type and exposure safeguards are fixed, the screenshots are sanitized, and the local security, authentication, Kubernetes, and Helm render contracts pass on 7ecfd92.
Three items remain before approval:
- Fix the latency metric lifecycle. agent-metrics.ts retains the last rolling latency samples indefinitely. If the final requests remain above the configured target after load stops, the custom metric can remain high and prevent HPA scale-down. A successful run can depend on the last samples happening to fall below the target. Please add an idle-expiration/reset behavior with a focused test, or remove latency as a selectable HPA signal.
- Align supported HPA modes and test coverage. values.yaml and the chart helpers still expose latency_p50, latency_p95, and request_rate, while the render contract tests only latency_avg. Please either restrict the built-in modes to the live-validated gpu and latency_avg signals, or add render/adapter contract coverage for every retained mode.
- Correct the verification record:
- git diff --check currently fails on trailing whitespace in README line 10.
- The checked Helm command, helm lint . --set ingress.allowInsecureHttp=true, fails because ingress.auth.htpasswd is required. Please use a valid reproducible lint command or adjust the chart defaults.
- Documentation review identifies 98c3bb4 as the reviewed head, but the current head is 7ecfd92. Please review the final changes and record the exact current head.
The prior source-path, Gateway path-type, screenshot-redaction, live-validation, and branch-update concerns are resolved.
Rename the GPU front door from agent to metrics-proxy, keep HPA modes to gpu_utilization and latency_avg with idle-expire and stepwise scale-down, and add local.env.example so TLS overlays work without host-specific exports.
Addressing latest review feedback (
|
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thanks for the thorough update. The three items from the previous review are resolved on 43b4f58: latency idle-expiration now has a focused passing contract, built-in HPA modes are restricted and tested, and the diff check, reproducible Helm lint, and documentation-review head are corrected. The repository, security, authentication, Kubernetes, metrics, and Helm render checks pass locally.
Two new blockers were introduced by this update:
-
Sanitize the committed screenshots again. docs/assets/hpa-scale-up.png and docs/assets/reference-4x-l40s.png show the specific Brev host name and a workspace path in the terminal prompt. This conflicts with the PR declaration that nonpublic host names and workspace paths are excluded. Please crop or redact those prompt lines. The latency screenshot still displays the legacy resource names but does not expose the host prompt.
-
Resolve and validate the Kubernetes resource rename. This commit renames the Deployment, Service, HPA, Gateway, Secrets, selectors, and scripts from *-agent to *-metrics-proxy. The supplied live evidence still shows nemoclaw-gpu-agent, so it does not validate the renamed topology. More importantly, the migration helper checks legacy labels on the new *-metrics-proxy Deployment name; an existing *-agent Deployment will not be found and removed, so an upgrade can leave both workloads running and competing for GPUs.
Please either:
- preserve the existing Kubernetes resource names and limit the clarity change to container labels/documentation, or
- implement a tested migration that detects and safely removes the old release resources, then provide live validation of install/upgrade, authenticated inference, HPA scale-up/down, Envoy distribution, and cleanup using the new names.
After the final screenshots or resource changes, update the documentation-review head again.
|
Hi NemoClaw team, I tried to ask CodeRabbit to do code review here but it didn't work, it worked for me at NVIDIA/NemoClaw, so I asked CodeRabbit team to check why it did not work here, here is the reply from them: "We found that CodeRabbit is connected to your fork but not to the NVIDIA/nemoclaw-community base repository, so the review command on PR 111 did not reach our review pipeline. Please ask an NVIDIA GitHub organization administrator to add nemoclaw-community to the CodeRabbit GitHub App's repository access, then retry @coderabbitai review. If the repository already appears authorized, please let us know so we can have our internal team re-sync its registration." I don't know who is the admin to ask, could you please help ask them, so the code in nemoclaw-community could get reviewed by CodeRabbit, thanks! |
Detect leftover agent-named Deployments/Services/HPAs/Gateways by basename and label, delete them (and orphaned keep Secrets) before Helm so upgrades cannot leave both workloads competing for GPUs; cover with a contract test and README upgrade note.
Updated README with new image links Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
Rename migration helpers to pre-metrics-proxy, clarify README that the GPU front door was never the AI agent, and drop leftover agent_containers variable names in render tests.
|
Clarification (per review discussion): the GPU front door is |
Live validation update (4× L40S,
|
apurvvkumaria
left a comment
There was a problem hiding this comment.
Thanks for the additional migration work and live evidence. The current-name migration behavior is now credible, and the branch remains current with main. Four items still need correction before approval:
-
Restore the sanitized screenshots. Commit 2f4db23 replaced the images with sanitized attachments, but 15442f9 reverted the README to docs/assets/reference-4x-l40s.png, docs/assets/hpa-scale-up.png, and the earlier latency attachment. The two committed images expose the specific Brev host name and workspace path, so the current README again conflicts with the release/compliance declaration.
-
Run migration before any Helm upgrade in every entry point. In hpa-load-test.sh, hpa_common_ensure_metrics_proxy_ready performs helm upgrade and waits for the new Deployment before hpa_common_migrate_pre_metrics_proxy_resources runs. hpa-reset.sh has the same ordering when DELETE_HPA=1. If the historical workload holds all available GPUs, the renamed workload can remain Pending and the script can fail before reaching migration. Move migration before hpa_common_ensure_metrics_proxy_ready in both scripts and add an ordering contract test.
-
Fix the security-contract cleanup. bash scripts/test-script-security-contract.sh currently prints its success line but exits nonzero because the EXIT trap leaves kubectl-migrate.log in TEST_TMP and rmdir fails. Include that file in cleanup or make cleanup remove the temporary directory safely, then verify the command returns exit code 0.
-
Update final review metadata. The PR records documentation review at 2f4db23, while the current head is 15442f9. After the final changes, review and record the exact final head.
The migration's legacy-resource detection and the contributor's live validation using *-metrics-proxy names are accepted; they do not need to be repeated unless the ordering fix changes runtime behavior.
Point README images at sanitized attachments and drop host-leaking docs/assets PNGs; migrate pre-metrics-proxy leftovers before ensure/helm in load-test and reset; fix security-contract temp cleanup exit status. Signed-off-by: maggiezha <maggiez@nvidia.com>
Addressing remaining review items (
|
Avoid slash wording that reads like division; both env vars default to allocatable GPU count. Signed-off-by: maggiezha <maggiez@nvidia.com>
Match the main README wording in scripts/README so MAX_REPLICAS and TARGET_PODS are not read as division. Signed-off-by: maggiezha <maggiez@nvidia.com>
Added images and additional PromQL queries for successful inference requests by pod in the README. Signed-off-by: maggiezha <42832776+maggiezha@users.noreply.github.com>
|
made small change to readme by adding Grafana screenshot and description of N, please see the latest head for final review: 15193cf |
apurvvkumaria
left a comment
There was a problem hiding this comment.
Approved at 15193cfd351867549ca372d8fb3eadc5fe233d37.
All previously requested changes are resolved. I reviewed the final documentation-only updates, including the replica-count clarification, PromQL examples, and sanitized Grafana screenshots. The branch is current with main, the required checks pass, and there are no unresolved review threads.
The timestamp-style screenshot alt text can be improved later as a non-blocking documentation refinement.
Thank you, could you please let me know which timestamp style screenshot, is that to show HPA scale up and down, or Grafana |
|
It refers to the two new Grafana images, specifically their HTML The current alt text is
This is non-blocking and does not require another update to this PR. |
Thanks! I can update ALT text next time together with something else coming |
Related Issue
This community recipe continues and re-homes the public work from NVIDIA/NemoClaw#7459 into
examples/recipes/nvidia/kubernetes-gpu-autoscaling/.Architecture follow-ups in this PR (beyond the imported baseline):
ENABLE_ENVOY_LB=0) and use the agent Service only. Replaces ingress-nginx when enabled. Envoy dataplane stays ClusterIP while the OpenShell cleartext HTTP listener is present.NVIDIA_API_KEY.AverageValue) — two documented examples: average per-pod GPU utilization > 40% and average per-pod LLM chat proxy latency > 3000 ms. These are examples; operators can choose other metrics or define their own customized Prometheus → Adapter → HPA metrics.Description
Add an experimental NVIDIA-authored Kubernetes recipe that runs a CPU-only NemoClaw/OpenClaw agent in an OpenShell sandbox and sends inference through Envoy Gateway (LeastRequest) to authenticated Ollama replicas on NVIDIA GPUs in the same cluster. A Kubernetes Horizontal Pod Autoscaler scales only the Ollama inference pods using Pods
AverageValuecustom metrics — documented examples are per-pod GPU utilization (gpu_utilization_percentvia DCGM → Prometheus → Adapter) and per-pod LLM latency (nemoclaw_llm_latency_avg_millisecondsvia metrics-proxy/metrics→ Prometheus → Adapter). Latency is the metrics-proxy chat/completions proxy duration (from just before the in-pod inference call until the full response is written to the client).The runtime path is entirely on-premises. HPA scales to N Ollama pods (1 GPU each); Envoy only changes load balancing (LeastRequest vs the agent ClusterIP Service when
ENABLE_ENVOY_LB=0):Operators can toggle Envoy with
ENABLE_ENVOY_LB/ingress.gateway.enabled, verify the sandbox path with./scripts/verify-nemoclaw-sandbox.sh, and keep the Envoy dataplane as ClusterIP while the OpenShell cleartext HTTP listener exists.Inference API key. The chart generates a local Secret for Bearer auth on model/chat; users do not supply a cloud key. OpenShell injects it for the sandbox path — not for Ollama model pulls, and not an OpenAI/
NVIDIA_API_KEYcredential. The sandbox policy removes and verifies removal of the inheritedintegrate.api.nvidia.comendpoint before the agent starts.Source migration
NVIDIA/NemoClawdeploy/helm/gpu_autoscaling_k8s/@77334cc(#7459)NVIDIA/nemoclaw-community: examples/recipes/nvidia/kubernetes-gpu-autoscaling/77334ccbbadba2c5079fe9e99fe80a3cddc846b5.v0.0.104atf389c9d872775006ae069473f58250fa8f3ad40f, OpenShell0.0.85, and Agent Sandboxv0.5.0.NemoClaw and OpenShell path
LeastRequest), which forwards Bearer-authenticated requests to the Ollama inference pods.0.0.85idle-sandbox lifecycle, capabilities, privilege-separation limitation, cleanup, and coordinated pin-update procedure.Security and lifecycle boundaries
NVIDIA_API_KEY. Timing-safe check on model/completion traffic (Authorization: Beareron the OpenShell/Envoy path, orX-Api-Keyfor external clients when Gateway Basic auth ownsAuthorization). Health, readiness, and metrics remain unauthenticated.NodePort/LoadBalancerin the chart and installer so that listener cannot bypass hostname-scoped HTTPS redirect and Basic auth when externally exposed.MAX_REPLICAS/TARGET_PODSto allocatable GPU count N (override only for an intentional lower ceiling).maxGpusdefault.This remains an unsupported, non-production community experiment; it does not establish native Kubernetes as a supported NemoClaw product surface.
Verification
python3 scripts/check_license_headers.py --checkpython3 scripts/check_label_taxonomy.pypython3 -m unittest scripts.tests.test_governance_taxonomypython3 scripts/check_pr_title.py --advisory 'feat(examples): add Kubernetes GPU autoscaling recipe'git diff --checkbash scripts/test-script-security-contract.shbash scripts/test-nemoclaw-k8s-contract.shnode scripts/test-inference-auth-contract.mjsbash scripts/test-render-contract.shwith Helm 3.20.2 onPATHhelm lint . --set ingress.allowInsecureHttp=true --set-string ingress.auth.htpasswd='demo:{SHA}<base64-sha1>'(Apache{SHA}htpasswd required by Envoy Gateway Basic auth)hostPathmain; it is zero commits behindmetrics.llmLatencyIdleExpireMs/LLM_LATENCY_IDLE_EXPIRE_MS(default 60s) resetsnemoclaw_llm_latency_avg_millisecondsafter idle so HPA can scale down; covered byscripts/test-metrics-proxy-metrics-contract.mjsgpu_utilizationandlatency_avg(retiredlatency_p50/latency_p95/request_rate; render contract rejects them). Mode-awarehpa-load-test.shviaHPA_METRIC=...*-agent→*-metrics-proxymigration:hpa_common_migrate_pre_metrics_proxy_resourcesdetects leftovers by basename and label, deletes them before ensure/Helm (install/reset/load-test); contract-tested; live-validated on 4× L40S (injected competingnemoclaw-gpu-agent, removed, then install + auth inference + HPA 1→2→1 + Envoy LeastRequest onnemoclaw-gpu-metrics-proxyonly)metrics-proxy(Ollama + metrics-proxy containers); OpenShell/NemoClaw AI agent remains CPU-only in the sandboxX-Api-Key; OpenShell-path Bearer through Envoy), HPA on GPU utilization (gpu_utilization_percent, average per-pod util > 40%) and LLM latency (nemoclaw_llm_latency_avg_milliseconds, average per-pod latency > 3000 ms) viahpa-load-test.sh, Envoy LeastRequest distribution check (concurrent chat completions across Ready GPU pods), OpenShell sandbox creation (nemoclaw-onprem), and authenticated model + chat/completions requests from the sandbox throughhttps://inference.local/v1(OpenShell → Envoy LeastRequest → Ollama).Documentation Writer Review
docs-updated970c1db890dc5fde2fcfb9a4dac4489ae396d72d(restores sanitized README screenshots; migration before ensure/helm in load-test/reset; security-contract cleanup exit 0; metrics-proxy naming + pre-metrics-proxy migration)Release And Compliance
.envfiles, private certificates, or token caches.THIRD-PARTY-NOTICES.Signed-off-by: maggiezha maggiez@nvidia.com